home *** CD-ROM | disk | FTP | other *** search
/ PC World 2006 February / PCWorld_2006-02_cd.bin / software / vyzkuste / triky / triky.exe / httrack-3.33.exe / {app} / src / htsname.c < prev    next >
C/C++ Source or Header  |  2005-02-05  |  50KB  |  1,442 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       savename routine (compute output filename)             */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. /* Internal engine bytecode */
  39. #define HTS_INTERNAL_BYTECODE
  40.  
  41. #include "htsname.h"
  42.  
  43. /* specific definitions */
  44. #include "htsbase.h"
  45. #include "htstools.h"
  46. #include "htsmd5.h"
  47. #include <ctype.h>
  48. /* END specific definitions */
  49.  
  50. #undef test_flush
  51. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  52.  
  53. #define ADD_STANDARD_PATH \
  54.     {  /* ajout nom */\
  55.       char BIGSTK buff[HTS_URLMAXSIZE*2];\
  56.       buff[0]='\0';\
  57.       strncatbuff(buff,start_pos,(int) (nom_pos - start_pos));\
  58.       url_savename_addstr(save,buff);\
  59.     }
  60.  
  61. #define ADD_STANDARD_NAME(shortname) \
  62.     {  /* ajout nom */\
  63.       char BIGSTK buff[HTS_URLMAXSIZE*2];\
  64.       standard_name(buff,dot_pos,nom_pos,fil_complete,(shortname));\
  65.       url_savename_addstr(save,buff);\
  66.     }
  67.  
  68.  
  69. /* Avoid stupid DOS system folders/file such as 'nul' */
  70. /* Based on linux/fs/umsdos/mangle.c */
  71. static const char *hts_tbdev[] =
  72. {
  73.     "/prn", "/con", "/aux", "/nul",
  74.     "/lpt1", "/lpt2", "/lpt3", "/lpt4",
  75.     "/com1", "/com2", "/com3", "/com4",
  76.     "/clock$",
  77.     "/emmxxxx0", "/xmsxxxx0", "/setverxx",
  78.     ""
  79. };
  80.  
  81.  
  82. #define URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET() do { \
  83.   int prev = _hts_in_html_parsing; \
  84.   while(back_pluggable_sockets_strict(back, back_max, opt) <= 0) { \
  85.     _hts_in_html_parsing = 6; \
  86.     /* Wait .. */ \
  87.     back_wait(back,back_max,opt,cache,0); \
  88.     /* Transfer rate */ \
  89.     engine_stats(); \
  90.     /* Refresh various stats */ \
  91.     HTS_STAT.stat_nsocket=back_nsoc(back,back_max); \
  92.     HTS_STAT.stat_errors=fspc(NULL,"error"); \
  93.     HTS_STAT.stat_warnings=fspc(NULL,"warning"); \
  94.     HTS_STAT.stat_infos=fspc(NULL,"info"); \
  95.     HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr); \
  96.     HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max); \
  97.     /* Check */ \
  98.     if (!hts_htmlcheck_loop(back,back_max,-1,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) { \
  99.       return -1; \
  100.     } \
  101.   } \
  102.   _hts_in_html_parsing = prev; \
  103. } while(0)
  104.  
  105.  
  106. // forme le nom du fichier α sauver (save) α partir de fil et adr
  107. // systΦme intelligent, qui renomme en cas de besoin (exemple: deux INDEX.HTML et index.html)
  108. int url_savename(char* adr_complete,char* fil_complete,char* save,char* former_adr,char* former_fil,char* referer_adr,char* referer_fil,httrackp* opt,lien_url** liens,int lien_tot,lien_back* back,int back_max,cache_back* cache,hash_struct* hash,int ptr,int numero_passe) {
  109.   char BIGSTK newfil[HTS_URLMAXSIZE*2];   /* ="" */
  110.   /*char BIGSTK normadr_[HTS_URLMAXSIZE*2];*/
  111.   char BIGSTK normadr_[HTS_URLMAXSIZE*2], normfil_[HTS_URLMAXSIZE*2];
  112.   int protocol = 0;
  113.   static const char* protocol_str[] = {"http", "https", "ftp", "file", "unknown"};
  114.   char* normadr;
  115.   char* normfil;
  116.   char* fil;
  117.   char* adr;
  118.   char* print_adr;
  119.   char *start_pos=NULL,*nom_pos=NULL,*dot_pos=NULL;  // Position nom et point
  120.   // pour changement d'extension ou de nom (content-disposition)
  121.   int ext_chg=0;
  122.   char ext[256];
  123.   int max_char=0;
  124.   //CLEAR
  125.   newfil[0]=ext[0]='\0';
  126.  
  127.   /* 8-3 ? */
  128.   switch(opt->savename_83) {
  129.   case 1:     // 8-3
  130.     max_char=8;
  131.     break;
  132.   case 2:     // Level 2 File names may be up to 31 characters.
  133.     max_char=31;
  134.     break;
  135.   default:
  136.     max_char=8;
  137.     break;
  138.   }
  139.  
  140.   // effacer save
  141.   save[0]='\0';
  142.   // fil
  143.   fil = fil_complete;
  144.   // copy of fil, used for lookups (see urlhack)
  145.   normfil = fil;
  146.   // et adr (sauter user/pass)
  147.   // on prend le parti de mettre les fichiers avec login/pass au mΩme endroit que si ils
  148.   // Θtaient capturΘs sans ces paramΦtres
  149.   // c'est pour cette raison qu'on ignore totalement adr_complete (mΩme pour la recherche en table de hachage)
  150.   adr = jump_identification(adr_complete);
  151.   // copy of adr, used for lookups (see urlhack)
  152.   normadr = adr;
  153.  
  154.   // normalize the URL:
  155.   // www.foo.com -> foo.com
  156.   // www-42.foo.com -> foo.com
  157.   // foo.com/bar//foobar -> foo.com/bar/foobar
  158.   if (opt->urlhack) {
  159.     // copy of adr (without protocol), used for lookups (see urlhack)
  160.     normadr=adr_normalized(adr, normadr_);
  161.     normfil=fil_normalized(fil,normfil_);
  162.   } else {
  163.     if (link_has_authority(adr_complete)) {     // https or other protocols : in "http/" subfolder
  164.       char* pos = strchr(adr_complete, ':');
  165.       if (pos != NULL) {
  166.         normadr_[0] = '\0';
  167.         strncatbuff(normadr_, adr_complete, (int)(pos - adr_complete));
  168.         strcatbuff(normadr_, "://");
  169.         strcatbuff(normadr_, normadr);
  170.         normadr=normadr_;
  171.       }
  172.     }
  173.   }
  174.  
  175.   // α afficher sans ftp://
  176.   print_adr=jump_protocol(adr);
  177.   if (strfield(adr_complete, "https:")) {
  178.       protocol = 1;
  179.   } else if (strfield(adr_complete, "ftp:")) {
  180.       protocol = 2;
  181.   } else if (strfield(adr_complete, "file:")) {
  182.       protocol = 3;
  183.   } else {
  184.       protocol = 0;
  185.   }
  186.  
  187.   // court-circuit pour lien primaire
  188.   if (strnotempty(adr)==0) {
  189.     if (strcmp(fil,"primary")==0) {
  190.       strcatbuff(save,"primary.html");
  191.       return 0;
  192.     }
  193.   }
  194.  
  195.  
  196.   // vΘrifier que le nom n'a pas dΘja ΘtΘ calculΘ (si oui le renvoyer tel que)
  197.   // vΘrifier que le nom n'est pas dΘja pris...
  198.   // NOTE: si on cherche /toto/ et que /toto est trouvΘ on le prend (et rΘciproquqment) ** // **
  199.   if (liens!=NULL) { 
  200.     int i;
  201.  
  202. #if HTS_HASH
  203.     i=hash_read(hash,normadr,normfil,1,opt->urlhack);      // recherche table 1 (adr+fil)
  204.     if (i>=0) {    // ok, trouvΘ
  205.       strcpybuff(save,liens[i]->sav);
  206.       return 0;
  207.     }
  208.     i=hash_read(hash,normadr,normfil,2,opt->urlhack);      // recherche table 2 (former_adr+former_fil)
  209.     if (i>=0) {    // ok, trouvΘ
  210.       // copier location moved!
  211.       strcpybuff(adr_complete,liens[i]->adr);
  212.       strcpybuff(fil_complete,liens[i]->fil);
  213.       // et save
  214.       strcpybuff(save,liens[i]->sav);  // copier (formΘ α partir du nouveau lien!)
  215.       return 0;
  216.     }
  217. #else
  218.     for(i=lien_tot-1;i>=0;i--) {        
  219. #if HTS_CASSE
  220.       if ((strcmp(liens[i]->adr,normadr)==0) && (strcmp(liens[i]->fil,normfil)==0))
  221. #else
  222.       if ((strfield2(liens[i]->adr,normadr)) && (strfield2(liens[i]->fil,normfil)))
  223. #endif
  224.       {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  225.         strcpybuff(save,liens[i]->sav);
  226.         return 0;
  227.       }
  228.       if (liens[i]->former_adr) {     // tester ancienne loc?
  229. #if HTS_CASSE
  230.         if ((strcmp(liens[i]->former_adr,normadr)==0) && (strcmp(liens[i]->former_fil,normfil)==0))
  231. #else
  232.         if ((strfield2(liens[i]->former_adr,normadr)) && (strfield2(liens[i]->former_fil,normfil)))
  233. #endif
  234.         {
  235.           // copier location moved!
  236.           strcpybuff(adr_complete,liens[i]->adr);
  237.           strcpybuff(fil_complete,liens[i]->fil);
  238.           // et save
  239.           strcpybuff(save,liens[i]->sav);  // copier (formΘ α partir du nouveau lien!)
  240.           return 0;
  241.         }
  242.       }
  243.     }
  244. #endif
  245.  
  246.     // chercher sans / ou avec / dans former
  247.     {
  248.       char BIGSTK fil_complete_patche[HTS_URLMAXSIZE*2];
  249.       strcpybuff(fil_complete_patche,normfil);
  250.       // Version avec ou sans /
  251.       if (fil_complete_patche[strlen(fil_complete_patche)-1]=='/')
  252.         fil_complete_patche[strlen(fil_complete_patche)-1]='\0';
  253.       else
  254.         strcatbuff(fil_complete_patche,"/");
  255. #if HTS_HASH
  256.       i=hash_read(hash,normadr,fil_complete_patche,2,opt->urlhack);      // recherche table 2 (former_adr+former_fil)
  257.       if (i>=0) {
  258.         // Θcraser fil et adr (pas former_fil?????)
  259.         strcpybuff(adr_complete,liens[i]->adr);
  260.         strcpybuff(fil_complete,liens[i]->fil);
  261.         // Θcrire save
  262.         strcpybuff(save,liens[i]->sav);
  263.         return 0;
  264.       }
  265. #else
  266.       // mΩme boucle en gros
  267.       for(i=lien_tot-1;i>=0;i--) {        
  268.         if (liens[i]->former_adr) {    // former-adr?
  269. #if HTS_CASSE
  270.           if ((strcmp(liens[i]->former_adr,normadr)==0) && (strcmp(liens[i]->former_fil,fil_complete_patche)==0))
  271. #else
  272.           if ((strfield2(liens[i]->former_adr,normadr)) && (strfield2(liens[i]->former_fil,fil_complete_patche)))
  273. #endif
  274.           {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  275.             // Θcraser fil et adr (pas former_fil?????)
  276.             strcpybuff(adr_complete,liens[i]->adr);
  277.             strcpybuff(fil_complete,liens[i]->fil);
  278.             // Θcrire save
  279.             strcpybuff(save,liens[i]->sav);
  280.             return 0;
  281.           }
  282.         }
  283.       }
  284. #endif
  285.     }
  286.   }
  287.  
  288.   // vΘrifier la non prΘsence de paramΦtres dans le nom de fichier
  289.   // si il y en a, les supprimer (ex: truc.cgi?subj=aspirateur)
  290.   // nΘanmoins, gardΘ pour vΘrifier la non duplication (voir aprΦs)
  291.   {
  292.     char* a;
  293.     a=strchr(fil,'?');
  294.     if (a!=NULL) {
  295.       strncatbuff(newfil,fil,(int) (a - fil));
  296.     } else {
  297.       strcpybuff(newfil,fil);
  298.     }
  299.     fil=newfil;
  300.   }
  301.   // dΘcoder %
  302.   strcpybuff(fil,unescape_http(fil));
  303.  
  304.   /* replace shtml to html.. */
  305.   switch (ishtml(fil)) {       /* .html,.shtml,.. */
  306.   case 1:
  307.     if ( 
  308.       (strfield2(get_ext(fil),"html") == 0)
  309.       && (strfield2(get_ext(fil),"htm") == 0)
  310.       ) {
  311.       strcpybuff(ext,"html");
  312.       ext_chg=1;
  313.     }
  314.     break;
  315.     case 0:
  316.       if (!strnotempty(ext)) {
  317.         if (is_userknowntype(get_ext(fil))) {      // mime known by user
  318.           char BIGSTK mime[1024];
  319.           mime[0]=ext[0]='\0';
  320.           get_userhttptype(0,mime,get_ext(fil));
  321.           if (strnotempty(mime)) {
  322.             give_mimext(ext,mime);
  323.             if (strnotempty(ext)) {
  324.               ext_chg=1;
  325.             }
  326.           }
  327.         }
  328.       }
  329.       break;
  330.   }
  331.   
  332.  
  333.   // si option check_type activΘe
  334.   if ((opt->check_type) && (!ext_chg)) {
  335.     int ishtest;
  336.     if ( (!strfield(adr_complete,"file://")) 
  337.       && (!strfield(adr_complete,"ftp://")) 
  338.       ) {
  339.       // tester type avec requΦte HEAD si on ne connait pas le type du fichier
  340.       if (!(   (opt->check_type==1) && (fil[strlen(fil)-1]=='/')   ))    // slash doit Ωtre html?
  341.       if ((ishtest=ishtml(fil)) < 0) { // on ne sait pas si c'est un html ou un fichier..
  342.         // lire dans le cache
  343.         htsblk r = cache_read(opt,cache,adr,fil,NULL,NULL);              // test uniquement
  344.         if (r.statuscode != -1) {  // pas d'erreur de lecture cache
  345.           char s[16]; s[0]='\0';
  346.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  347.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type (from cache) %s%s"LF,adr_complete,fil_complete);
  348.             test_flush;
  349.           }
  350.           if (strnotempty(r.cdispo)) {        /* filename given */
  351.             ext_chg=2;      /* change filename */
  352.             strcpybuff(ext,r.cdispo);
  353.           }
  354.           else if (!may_unknown(r.contenttype) || ishtest == -2) {  // on peut patcher α priori?
  355.             give_mimext(s,r.contenttype);  // obtenir extension
  356.             if (strnotempty(s)>0) {        // on a reconnu l'extension
  357.               ext_chg=1;
  358.               strcpybuff(ext,s);
  359.             }
  360.           }
  361.           //
  362.         } else if (is_userknowntype(fil)) {   /* PATCH BY BRIAN SCHR╓DER. 
  363.                                                  Lookup mimetype not only by extension, 
  364.                                                  but also by filename */
  365.           /* Note: "foo.cgi => text/html" means that foo.cgi shall have the text/html MIME file type,
  366.              that is, ".html" */
  367.           char BIGSTK mime[1024];
  368.           mime[0]=ext[0]='\0';
  369.           get_userhttptype(0, mime, fil);
  370.           if (strnotempty(mime)) {
  371.             give_mimext(ext, mime);
  372.             if (strnotempty(ext)) {
  373.               ext_chg=1;
  374.             }
  375.           }
  376.         } else {          // test imposible dans le cache, faire une requΩte
  377.           //
  378. #if HTS_ANALYSTE
  379.           int hihp=_hts_in_html_parsing;
  380. #endif
  381.           int has_been_moved=0;
  382.           char BIGSTK curr_adr[HTS_URLMAXSIZE*2],curr_fil[HTS_URLMAXSIZE*2];
  383.           
  384.           /* Ensure we don't use too many sockets by using a "testing" one
  385.              If we have only 1 simultaneous connection authorized, wait for pending download
  386.              Wait for an available slot 
  387.           */
  388.           URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET();
  389.  
  390.           /* Rock'in */
  391.           curr_adr[0]=curr_fil[0]='\0';
  392. #if HTS_ANALYSTE
  393.           _hts_in_html_parsing=2;  // test
  394. #endif
  395.           if ( (opt->debug>1) && (opt->log!=NULL) ) {
  396.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type %s%s"LF,adr_complete,fil_complete);
  397.             test_flush;
  398.           }
  399.           strcpybuff(curr_adr,adr_complete);
  400.           strcpybuff(curr_fil,fil_complete);
  401.           // ajouter dans le backing le fichier en mode test
  402.           // savename: rien car en mode test
  403.           if (back_add(back,back_max,opt,cache,curr_adr,curr_fil,BACK_ADD_TEST,referer_adr,referer_fil,1,NULL)!=-1) {
  404.             int b;
  405.             b=back_index(back,back_max,curr_adr,curr_fil,BACK_ADD_TEST);         
  406.             if (b>=0) {
  407.               int stop_looping=0;
  408.               int petits_tours=0;
  409.               int get_test_request=0;       // en cas de bouclage sur soi mΩme avec HEAD, tester avec GET.. parfois c'est la cause des problΦmes
  410.               do {
  411.                 // temps α attendre, et remplir autant que l'on peut le cache (backing)
  412.                 if (back[b].status>0) {
  413.                   back_wait(back,back_max,opt,cache,0);        
  414.                 }
  415.                 if (ptr>=0) {
  416.                   back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  417.                 }
  418.   
  419.                 // on est obligΘ d'appeler le shell pour le refresh..
  420. #if HTS_ANALYSTE
  421.                 {
  422.                   
  423.                   // Transfer rate
  424.                   engine_stats();
  425.                   
  426.                   // Refresh various stats
  427.                   HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
  428.                   HTS_STAT.stat_errors=fspc(NULL,"error");
  429.                   HTS_STAT.stat_warnings=fspc(NULL,"warning");
  430.                   HTS_STAT.stat_infos=fspc(NULL,"info");
  431.                   HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
  432.                   HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  433.  
  434.                   if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
  435.                     return -1;
  436.                   } else if (_hts_cancel || !back_checkmirror(opt)) {    // cancel 2 ou 1 (cancel parsing)
  437.                     back_delete(opt,cache,back,b);       // cancel test
  438.                     stop_looping = 1;
  439.                   }
  440.                 }
  441. #endif
  442.                 
  443.                 
  444.                 // traitement des 304,303..
  445.                 if (back[b].status<=0) {
  446.                   if (    (back[b].r.statuscode==301)
  447.                        || (back[b].r.statuscode==302)
  448.                        || (back[b].r.statuscode==303)
  449.                        || (back[b].r.statuscode==307)
  450.                      ) {    // agh moved.. un tit tour de plus
  451.                     if ((petits_tours<5) && (former_adr) && (former_fil)) { // on va pas tourner en rond non plus!
  452.                       if ((int) strnotempty(back[b].r.location)) {    // location existe!
  453.                         char BIGSTK mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2];
  454.                         mov_url[0]=mov_adr[0]=mov_fil[0]='\0';
  455.                         //
  456.                         strcpybuff(mov_url,back[b].r.location);    // copier URL
  457.                         if (ident_url_relatif(mov_url,curr_adr,curr_fil,mov_adr,mov_fil)>=0) {                        
  458.                           // si non bouclage sur soi mΩme, ou si test avec GET non testΘ
  459.                           if ((strcmp(mov_adr,curr_adr)) || (strcmp(mov_fil,curr_fil)) || (get_test_request==0)) {
  460.                             // bouclage?
  461.                             if ((!strcmp(mov_adr,curr_adr)) && (!strcmp(mov_fil,curr_fil)))
  462.                               get_test_request=1;     // faire requΦte avec GET
  463.  
  464.                             // recopier former_adr/fil?
  465.                             if ((former_adr) && (former_fil)) {
  466.                               if (strnotempty(former_adr)==0) {    // Pas dΘja notΘ
  467.                                 strcpybuff(former_adr,curr_adr);
  468.                                 strcpybuff(former_fil,curr_fil);
  469.                               }
  470.                             }
  471.  
  472.                             // check explicit forbidden - don't follow 3xx in this case
  473.                             {
  474.                               int set_prio_to=0;
  475.                               robots_wizard* robots = (robots_wizard*) opt->robotsptr;
  476.                               if (hts_acceptlink(opt,ptr,lien_tot,liens,
  477.                                 mov_adr,mov_fil,
  478.                                 NULL, NULL,
  479.                                 &set_prio_to,
  480.                                 NULL) == 1) 
  481.                               {  /* forbidden */
  482.                                 has_been_moved = 1;
  483.                                 back_maydelete(opt,cache,back,b);    // ok
  484.                                 strcpybuff(curr_adr,mov_adr);
  485.                                 strcpybuff(curr_fil,mov_fil);
  486.                                 mov_url[0]='\0';
  487.                                 stop_looping = 1;
  488.                               }
  489.                             }
  490.                             
  491.                             // ftp: stop!
  492.                             if (strfield(mov_url,"ftp://")) {    // ftp, ok on arrΩte
  493.                               has_been_moved = 1;
  494.                               back_maydelete(opt,cache,back,b);    // ok
  495.                               strcpybuff(curr_adr,mov_adr);
  496.                               strcpybuff(curr_fil,mov_fil);
  497.                               stop_looping = 1;
  498.                             } else if (*mov_url) {
  499.                               char* methode;
  500.                               if (!get_test_request)
  501.                                 methode=BACK_ADD_TEST;      // tester avec HEAD
  502.                               else {
  503.                                 methode=BACK_ADD_TEST2;     // tester avec GET
  504.                                 if ( opt->errlog!=NULL ) {
  505.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Loop with HEAD request (during prefetch) at %s%s"LF,curr_adr,curr_fil);
  506.                                   test_flush;
  507.                                 }                    
  508.                               }
  509.                               // Ajouter
  510.                               URLSAVENAME_WAIT_FOR_AVAILABLE_SOCKET();
  511.                               if (back_add(back,back_max,opt,cache,mov_adr,mov_fil,methode,referer_adr,referer_fil,1,NULL)!=-1) {    // OK
  512.                                 if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  513.                                   fspc(opt->errlog,"warning"); fprintf(opt->errlog,"(during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  514.                                   test_flush;
  515.                                 }
  516.                                 
  517.                                 // libΘrer emplacement backing actuel et attendre le prochain
  518.                                 back_maydelete(opt,cache,back,b);
  519.                                 strcpybuff(curr_adr,mov_adr);
  520.                                 strcpybuff(curr_fil,mov_fil);
  521.                                 b=back_index(back,back_max,curr_adr,curr_fil,methode);         
  522.                                 if (!get_test_request)
  523.                                   has_been_moved = 1;       // sinon ne pas forcer has_been_moved car non dΘplacΘ
  524.                                 petits_tours++;
  525.                                 //
  526.                               } else {// sinon on fait rien et on s'en va.. (ftp etc)
  527.                                 if ( (opt->debug>1)  && (opt->errlog)) {
  528.                                   fspc(opt->errlog,"debug"); fprintf(opt->errlog,"Warning: Savename redirect backing error at %s%s"LF,mov_adr,mov_fil);
  529.                                   test_flush;
  530.                                 } 
  531.                               }
  532.                             }
  533.                           } else {
  534.                             if ( opt->errlog!=NULL ) {
  535.                               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop to same filename)"LF,adr_complete,fil_complete);
  536.                               test_flush;
  537.                             }
  538.                           }
  539.                           
  540.                         }
  541.                       }
  542.                     } else{  // arrΩter les frais
  543.                       if ( opt->errlog!=NULL ) {
  544.                         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop)"LF,adr_complete,fil_complete);
  545.                         test_flush;
  546.                       }
  547.                     }
  548.                   }  // ok, leaving
  549.                 }
  550.               } while(!stop_looping && back[b].status > 0 && back[b].status < 1000);
  551.               
  552.               // Si non dΘplacΘ, forcer type?
  553.               if (!has_been_moved) {
  554.                 if (back[b].r.statuscode!=-10) {    // erreur
  555.                   if (strnotempty(back[b].r.contenttype)==0)
  556.                     strcpybuff(back[b].r.contenttype,"text/html");    // message d'erreur en html
  557.                   // Finalement on, renvoie un erreur, pour ne toucher α rien dans le code
  558.                   // libΘrer emplacement backing
  559.                   /*if (opt->errlog!=NULL) {
  560.                     fspc(opt->errlog,0); fprintf(opt->errlog,"Error: (during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil);
  561.                     test_flush;
  562.                   }                    
  563.                   back_delete(opt,cache,back,b);
  564.                   return -1;        // ERREUR (404 par exemple)
  565.                   */
  566.                 } 
  567.                 
  568.                 {            // pas d'erreur, changer type?
  569.                   char s[16];
  570.                   s[0]='\0';
  571.                   if (strnotempty(back[b].r.cdispo)) {        /* filename given */
  572.                     ext_chg=2;      /* change filename */
  573.                     strcpybuff(ext,back[b].r.cdispo);
  574.                   }
  575.                   else if (!may_unknown(back[b].r.contenttype) || ishtest == -2 ) {  // on peut patcher α priori? (pas interdit ou pas de type)
  576.                     give_mimext(s,back[b].r.contenttype);  // obtenir extension
  577.                     if (strnotempty(s)>0) {    // on a reconnu l'extension
  578.                       ext_chg=1;
  579.                       strcpybuff(ext,s);
  580.                     }
  581.                   }
  582.                 }
  583.               }
  584.               // FIN Si non dΘplacΘ, forcer type?
  585.  
  586.               // libΘrer emplacement backing
  587.               back_maydelete(opt,cache,back,b);
  588.               
  589.               // --- --- ---
  590.               // oops, a ΘtΘ dΘplacΘ.. on recalcule en rΘcursif (osons!)
  591.               if (has_been_moved) {
  592.                 // copier adr, fil (optionnel, mais sinon marche pas pour le rip)
  593.                 strcpybuff(adr_complete,curr_adr);
  594.                 strcpybuff(fil_complete,curr_fil);
  595.                 // copier adr, fil
  596.                 
  597.                 return url_savename(curr_adr,curr_fil,save,NULL,NULL,referer_adr,referer_fil,opt,liens,lien_tot,back,back_max,cache,hash,ptr,numero_passe);
  598.               }
  599.               // --- --- ---
  600.               
  601.             }
  602.             
  603.           } else {
  604.             printf("PANIC! : Savename Crash adding error, unexpected error found.. [%d]\n",__LINE__);
  605. #if BDEBUG==1
  606.             printf("error while savename crash adding\n");
  607. #endif
  608.             if (opt->errlog) {
  609.               fspc(opt->errlog,"error"); fprintf(opt->errlog,"Unexpected savename backing error at %s%s"LF,adr,fil_complete);
  610.               test_flush;
  611.             } 
  612.             
  613.           }
  614.           // restaurer
  615. #if HTS_ANALYSTE
  616.           _hts_in_html_parsing=hihp;
  617. #endif
  618.         }  // cachΘ?
  619.       }
  620.     }
  621.   }
  622.  
  623.  
  624.  
  625.   // - - - DEBUT NOMMAGE - - -
  626.  
  627.   // Donner nom par dΘfaut?
  628.   if (fil[strlen(fil)-1]=='/')  {
  629.     if (!strfield(adr_complete,"ftp://"))
  630.       strcatbuff(fil,DEFAULT_HTML);     // nommer page par dΘfaut!!
  631.     else {
  632.       if (!opt->proxy.active)
  633.         strcatbuff(fil,DEFAULT_FTP);     // nommer page par dΘfaut (texte)
  634.       else
  635.         strcatbuff(fil,DEFAULT_HTML);     // nommer page par dΘfaut (α priori ici html depuis un proxy http)
  636.     }
  637.   }
  638.   // Changer extension?
  639.   // par exemple, php3 sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  640.   if (ext_chg) {  // changer ext
  641.     char* a=fil+strlen(fil)-1;
  642.     if ( (opt->debug>1) && (opt->log!=NULL) ) {
  643.       fspc(opt->log,"debug");
  644.       if (ext_chg==1)
  645.         fprintf(opt->log,"Changing link extension %s%s to .%s"LF,adr_complete,fil_complete,ext);
  646.       else
  647.         fprintf(opt->log,"Changing link name %s%s to %s"LF,adr_complete,fil_complete,ext);
  648.       test_flush;
  649.     }
  650.     if (ext_chg==1) {
  651.       while((a > fil) && (*a!='.') && (*a!='/')) a--;
  652.       if (*a=='.') *a='\0';  // couper
  653.       strcatbuff(fil,".");      // recopier point
  654.     } else {
  655.       while(( a > fil) && (*a!='/')) a--;
  656.       if (*a=='/') a++;
  657.       *a='\0';
  658.    }
  659.     strcatbuff(fil,ext);    // copier ext/nom
  660.   }
  661.  
  662.   // Rechercher premier / et dernier .
  663.   {  
  664.     char* a=fil+strlen(fil)-1;
  665.  
  666.     // passer structures
  667.     start_pos=fil;
  668.     while(( a > fil) && (*a != '/') && (*a != '\\')) {
  669.       if (*a == '.')    // point? noter position
  670.         if (!dot_pos)
  671.           dot_pos=a;
  672.         a--;
  673.     }
  674.     if ((*a=='/') || (*a=='\\')) a++;
  675.     nom_pos = a;
  676.   }
  677.  
  678.   
  679.   // un nom de fichier est gΘnΘrΘ
  680.   // s'il existe dΘja, alors on le mofifie lΘgΦrement
  681.  
  682.   // ajouter nom du site Θventuellement en premier
  683.   if (opt->savename_type == -1) {    // utiliser savename_userdef! (%h%p/%n%q.%t)
  684.     char* a = opt->savename_userdef;
  685.     char* b = save;
  686.     /*char *nom_pos=NULL,*dot_pos=NULL;  // Position nom et point */
  687.     char tok;
  688.  
  689.     /*
  690.     {  // Rechercher premier /
  691.       char* a=fil+strlen(fil)-1;
  692.       // passer structures
  693.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) {
  694.         if (*a == '.')    // point? noter position
  695.         if (!dot_pos)
  696.           dot_pos=a;
  697.         a--;
  698.       }
  699.       if ((*a=='/') || (*a=='\\')) a++;
  700.       nom_pos = a;
  701.     }
  702.     */
  703.  
  704.     // Construire nom
  705.     while ((*a) && (((int) (b - save)) < HTS_URLMAXSIZE ) ) {    // parser, et pas trop long..
  706.       if (*a == '%') {
  707.         int short_ver=0;
  708.         a++;
  709.         if (*a == 's') {
  710.           short_ver=1;
  711.           a++;
  712.         }
  713.         *b='\0';
  714.         switch(tok=*a++) {
  715.           case '[':            // %[param:prefix_if_not_empty:suffix_if_not_empty:empty_replacement:notfound_replacement]
  716.             if (strchr(a,']')) {
  717.               int pos=0;
  718.               char name[5][256];
  719.               char* c=name[0];
  720.               for(pos = 0 ; pos < 5 ; pos++) {
  721.                 name[pos][0]='\0';
  722.               }
  723.               pos=0;
  724.               while(*a!=']') {
  725.                 if (pos < 5) {
  726.                   if (*a == ':') {  // next token
  727.                     c=name[++pos];
  728.                     a++;
  729.                   } else {
  730.                     *c++=*a++;
  731.                     *c='\0';
  732.                   }
  733.                 }
  734.               }
  735.               a++;
  736.               strcatbuff(name[0],"=");           /* param=.. */
  737.               c=strchr(fil_complete,'?');
  738.               /* parameters exists */
  739.               if (c) {
  740.                 char* cp;
  741.                 while((cp = strstr(c+1, name[0])) && *(cp-1) != '?' && *(cp-1) != '&') {     /* finds [?&]param= */
  742.                   c = cp;
  743.                 }
  744.                 if (cp) {
  745.                   c = cp + strlen(name[0]);    /* jumps "param=" */
  746.                   strcpybuff(b, name[1]);    /* prefix */
  747.                   b += strlen(b);
  748.                   if (*c != '\0' && *c != '&') {
  749.                     char* d = name[0];
  750.                     /* */
  751.                     while(*c != '\0' && *c != '&') {
  752.                       *d++ = *c++;
  753.                     }
  754.                     *d = '\0';
  755.                     d = unescape_http(name[0]);
  756.                     if (d && *d) {
  757.                       strcpybuff(b, d);         /* value */
  758.                       b += strlen(b);
  759.                     } else {
  760.                       strcpybuff(b, name[3]);    /* empty replacement if any */
  761.                       b += strlen(b);
  762.                     }
  763.                   } else {
  764.                     strcpybuff(b, name[3]);    /* empty replacement if any */
  765.                     b += strlen(b);
  766.                   }
  767.                   strcpybuff(b, name[2]);    /* suffix */
  768.                   b += strlen(b);
  769.                 } else {
  770.                   strcpybuff(b, name[4]);    /* not found replacement if any */
  771.                   b += strlen(b);
  772.                 }
  773.               }
  774.             }
  775.           break;
  776.           case '%': *b++='%'; break;
  777.           case 'n':    // nom sans ext
  778.             if (dot_pos) {
  779.               if (!short_ver)    // Noms longs
  780.                 strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  781.               else
  782.                 strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  783.             } else {
  784.               if (!short_ver)    // Noms longs
  785.                 strcpybuff(b,nom_pos);
  786.               else
  787.                 strncatbuff(b,nom_pos,8);
  788.             }
  789.             b+=strlen(b);   // pointer α la fin
  790.             break;
  791.           case 'N':    // nom avec ext
  792.             // RECOPIE NOM + EXT
  793.             *b='\0';
  794.             if (dot_pos) {
  795.               if (!short_ver)    // Noms longs
  796.                 strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  797.               else
  798.                 strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  799.             } else {
  800.               if (!short_ver)    // Noms longs
  801.                 strcpybuff(b,nom_pos);
  802.               else
  803.                 strncatbuff(b,nom_pos,8);
  804.             }
  805.             b+=strlen(b);   // pointer α la fin
  806.             // RECOPIE NOM + EXT
  807.             *b='\0';
  808.             if (dot_pos) {
  809.               if (!short_ver)    // Noms longs
  810.                 strcpybuff(b,dot_pos+1);
  811.               else
  812.                 strncatbuff(b,dot_pos+1,3);
  813.             } else {
  814.               if (!short_ver)    // Noms longs
  815.                 strcpybuff(b,DEFAULT_EXT);    // pas de..
  816.               else
  817.                 strcpybuff(b,DEFAULT_EXT_SHORT);    // pas de..
  818.             }
  819.             b+=strlen(b);   // pointer α la fin
  820.             //
  821.             break;
  822.           case 't':    // ext
  823.             *b='\0';
  824.             if (dot_pos) {
  825.               if (!short_ver)    // Noms longs
  826.                 strcpybuff(b,dot_pos+1);
  827.               else
  828.                 strncatbuff(b,dot_pos+1,3);
  829.             } else {
  830.               if (!short_ver)    // Noms longs
  831.                 strcpybuff(b,DEFAULT_EXT);    // pas de..
  832.               else
  833.                 strcpybuff(b,DEFAULT_EXT_SHORT);    // pas de..
  834.             }
  835.             b+=strlen(b);   // pointer α la fin
  836.             break;
  837.           case 'p':    // path sans dernier /
  838.             *b='\0';
  839.             if (nom_pos != fil + 1) { // pas: /index.html (chemin nul)
  840.               if (!short_ver) {   // Noms longs
  841.                 strncatbuff(b,fil,(int) (nom_pos - fil) - 1);
  842.               } else {
  843.                 char BIGSTK pth[HTS_URLMAXSIZE*2],n83[HTS_URLMAXSIZE*2];
  844.                 pth[0]=n83[0]='\0';
  845.                 //
  846.                 strncatbuff(pth,fil,(int) (nom_pos - fil) - 1);
  847.                 long_to_83(opt->savename_83,n83,pth);
  848.                 strcpybuff(b,n83);
  849.               }
  850.             }
  851.             b+=strlen(b);   // pointer α la fin
  852.             break;
  853.           case 'h':    // host
  854.             *b='\0';
  855.             if (strcmp(adr_complete,"file://")==0) {
  856.               if (!short_ver)    // Noms longs
  857.                 strcpybuff(b,"localhost");
  858.               else
  859.                 strcpybuff(b,"local");
  860.             } else {
  861.               if (!short_ver)    // Noms longs
  862.                 strcpybuff(b,print_adr);
  863.               else
  864.                 strncatbuff(b,print_adr,8);
  865.             }
  866.             b+=strlen(b);   // pointer α la fin
  867.             break;
  868.           case 'M':         /* host/address?query MD5 (128-bits) */
  869.             *b='\0';
  870.             {
  871.               char digest[32+2];
  872.               char BIGSTK buff[HTS_URLMAXSIZE*2];
  873.               digest[0]=buff[0]='\0';
  874.               strcpybuff(buff,adr);
  875.               strcatbuff(buff,fil_complete);
  876.               domd5mem(buff,strlen(buff),digest,1);
  877.               strcpybuff(b,digest);
  878.             }
  879.             b+=strlen(b);   // pointer α la fin
  880.             break;
  881.           case 'Q': case 'q':         /* query MD5 (128-bits/16-bits) 
  882.                                          GENERATED ONLY IF query string exists! */
  883.             *b='\0';
  884.             strncatbuff(b,url_md5(fil_complete),(tok == 'Q')?32:4);
  885.             b+=strlen(b);   // pointer α la fin
  886.             break;
  887.           case 'r': case 'R':        // protocol
  888.             *b='\0';
  889.             strcatbuff(b, protocol_str[protocol]);
  890.             b+=strlen(b);   // pointer α la fin
  891.           break;
  892.         }
  893.       } else
  894.         *b++=*a++;
  895.     }
  896.     *b++='\0';
  897.     //
  898.     // Types prΘdΘfinis
  899.     //
  900.  
  901.   } 
  902.   //
  903.   // Structure originale
  904.   else if (opt->savename_type%100==0) { 
  905.     /* recopier www.. */
  906.     if (opt->savename_type!=100) {  
  907.       if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  908.         if (strcmp(adr_complete,"file://")==0) {
  909.           //## if (*adr==lOCAL_CHAR) {
  910.           if (opt->savename_83 != 1)  // noms longs
  911.             strcatbuff(save,"localhost");
  912.           else
  913.             strcatbuff(save,"local");
  914.         } else {
  915.           // adresse url
  916.           if (!opt->savename_83) {  // noms longs (et pas de .)
  917.             strcatbuff(save,print_adr);
  918.           } else {  // noms 8-3
  919.             if (strlen(print_adr)>4) {
  920.               if (strfield(print_adr,"www."))
  921.                 strncatbuff(save,print_adr+4,max_char);
  922.               else
  923.                 strncatbuff(save,print_adr,8);
  924.             } else strncatbuff(save,print_adr,max_char);
  925.           }
  926.         }
  927.         if (*fil!='/') strcatbuff(save,"/");
  928.       }
  929.     }
  930.   
  931. #if HTS_CASSE==0
  932.     hts_lowcase(save);
  933. #endif  
  934.         
  935.     /*
  936.     // ne sert α rien car a dΘja ΘtΘ filtrΘ normalement
  937.     if ((*fil=='.') && (*(fil+1)=='/'))          // ./index.html ** //
  938.       url_savename_addstr(save,fil+2);
  939.     else                                               // index.html ou /index.html
  940.       url_savename_addstr(save,fil);
  941.     if (save[strlen(save)-1]=='/') 
  942.       strcatbuff(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  943. */
  944.  
  945.     /* add name */
  946.     ADD_STANDARD_PATH;
  947.     ADD_STANDARD_NAME(0);
  948.  
  949.   }
  950.   //
  951.   // Structure html/image
  952.   else {    
  953.     // dossier "web" ou "www.xxx" ?
  954.     if (((opt->savename_type/1000)%2)==0) {    // >1000 signifie "pas de www/"
  955.       if ((opt->savename_type/100)%2) {
  956.         if (strcmp(adr_complete,"file://")==0) {
  957.         //## if (*adr==lOCAL_CHAR) {
  958.           if (opt->savename_83 != 1)  // noms longs
  959.             strcatbuff(save,"localhost/");
  960.           else
  961.             strcatbuff(save,"local/");
  962.         } else {
  963.           // adresse url
  964.           if (!opt->savename_83) {  // noms longs
  965.             strcatbuff(save,print_adr); strcatbuff(save,"/");
  966.           } else {  // noms 8-3
  967.             if (strlen(print_adr)>4) {
  968.               if (strfield(print_adr,"www."))
  969.                 strncatbuff(save,print_adr+4,max_char);
  970.               else
  971.                 strncatbuff(save,print_adr,max_char);
  972.               strcatbuff(save,"/");
  973.             } else { 
  974.               strncatbuff(save,print_adr,max_char); strcatbuff(save,"/");
  975.             }
  976.           }
  977.         }
  978.       } else {
  979.         strcatbuff(save,"web/");    // rΘpertoire gΘnΘral
  980.       }
  981.     } 
  982.  
  983.     // si un html α coup s√r
  984.     if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  985.       if (opt->savename_type%100==2) {  // html/
  986.         strcatbuff(save,"html/");
  987.       }
  988.     } else {
  989.       if ((opt->savename_type%100==1) || (opt->savename_type%100==2)) {  // html & images
  990.         strcatbuff(save,"images/");
  991.       }
  992.     }
  993.     
  994.     switch (opt->savename_type%100) {
  995.     case 4: case 5: {           // sΘparer par types
  996.       char* a=fil+strlen(fil)-1;
  997.       // passer structures
  998.       while(( a > fil) && (*a != '/') && (*a != '\\')) a--;      
  999.       if ((*a=='/') || (*a=='\\')) a++;
  1000.  
  1001.       // html?
  1002.       if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) {
  1003.         if (opt->savename_type%100==5)
  1004.           strcatbuff(save,"html/");
  1005.       } else {
  1006.         char* a=fil+strlen(fil)-1;
  1007.         while(( a> fil) && (*a != '/') && (*a != '.')) a--;      
  1008.         if (*a!='.')
  1009.           strcatbuff(save,"other");
  1010.         else
  1011.           strcatbuff(save,a+1);
  1012.         strcatbuff(save,"/");
  1013.       }
  1014.       /*strcatbuff(save,a);*/
  1015.       /* add name */
  1016.       ADD_STANDARD_NAME(0);
  1017.             }
  1018.       break;
  1019.     case 99: {                  // 'codΘ' .. c'est un gadget
  1020.       int i;
  1021.       int j;
  1022.       char* a;
  1023.       char C[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
  1024.       int L;
  1025.       // pseudo-CRC sur fil et adr pour initialiser gΘnΘrateur alΘatoire..
  1026.       unsigned int s=0;
  1027.       L=strlen(C);
  1028.       for(i=0;i<(int) strlen(fil_complete);i++) {
  1029.         s+=(unsigned int) fil_complete[i];
  1030.       }
  1031.       for(i=0;i<(int) strlen(adr_complete);i++) {
  1032.         s+=(unsigned int) adr_complete[i];
  1033.       }
  1034.       srand(s);
  1035.       
  1036.       j=strlen(save);
  1037.       for(i=0;i<8;i++) {
  1038.         char c=C[(rand()%L)];
  1039.         save[i+j]=c;
  1040.       }
  1041.       save[i+j]='\0';
  1042.       // ajouter extension
  1043.       a=fil+strlen(fil)-1;
  1044.       while(( a > fil) && (*a != '/') && (*a != '.')) a--;
  1045.       if (*a=='.') {
  1046.         strcatbuff(save,a);    // ajouter
  1047.       }
  1048.              } 
  1049.       break;
  1050.     default: {   // noms sans les noms des rΘpertoires
  1051.       // ne garder que le nom, pas la structure
  1052.       /*
  1053.       char* a=fil+strlen(fil)-1;
  1054.       while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) a--;      
  1055.       if ((*a=='/') || (*a=='\\')) a++;
  1056.       strcatbuff(save,a);
  1057.       */
  1058.  
  1059.       /* add name */
  1060.       ADD_STANDARD_NAME(0);
  1061.             }
  1062.       break;
  1063.     }
  1064.  
  1065. #if HTS_CASSE==0
  1066.     hts_lowcase(save);
  1067. #endif  
  1068.  
  1069.     if (save[strlen(save)-1]=='/') 
  1070.       strcatbuff(save,DEFAULT_HTML);     // nommer page par dΘfaut!!
  1071.   }
  1072.  
  1073.  
  1074.   // vΘrifier qu'on ne doit pas forcer l'extension
  1075.   // par exemple, asp sera sauvΘ en html, cgi en html ou gif, xbm etc.. selon les cas
  1076.   /*if (ext_chg) {
  1077.     char* a=save+strlen(save)-1;
  1078.     while(((int) a>(int) save) && (*a!='.') && (*a!='/')) a--;
  1079.     if (*a=='.') *a='\0';  // couper
  1080.     // recopier extension
  1081.     strcatbuff(save,".");
  1082.     strcatbuff(save,ext);    // copier ext
  1083.   }*/
  1084.   // de mΩme en cas de manque d'extension on en place une de maniΦre forcΘe..
  1085.   // cela Θvite les /chez/toto et les /chez/toto/index.html incompatibles
  1086.   if (opt->savename_type != -1) {
  1087.     char* a=save+strlen(save)-1;
  1088.     while(( a > save) && (*a!='.') && (*a!='/')) a--;
  1089.     if (*a!='.') {   // agh pas de point
  1090.       //strcatbuff(save,".none");                 // a Θviter
  1091.       strcatbuff(save,".html");                   // prΘfΘrable!
  1092.       if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  1093.         fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Default HTML type set for %s%s"LF,adr_complete,fil_complete);
  1094.         test_flush;
  1095.       }
  1096.     }
  1097.   }
  1098.  
  1099.   // effacer pass au besoin pour les autentifications
  1100.   // (plus la peine : masquΘ au dΘbut)
  1101. /*
  1102.   {
  1103.     char* a=jump_identification(save);
  1104.     if (a!=save) {
  1105.       char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1106.       char *b;
  1107.       tempo[0]='\0';
  1108.       strcpybuff(tempo,"[");
  1109.       b=strchr(save,':');
  1110.       if (!b) b=strchr(save,'@');
  1111.       if (b)
  1112.         strncatbuff(tempo,save,(int) b-(int) a);
  1113.       strcatbuff(tempo,"]");
  1114.       strcatbuff(tempo,a);
  1115.       strcpybuff(save,a);
  1116.     }
  1117.   }
  1118. */
  1119.  
  1120.   // Θviter les / au dΘbut (cause: N100)
  1121.   if (save[0]=='/') {
  1122.     char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1123.     strcpybuff(tempo,save+1);
  1124.     strcpybuff(save,tempo);
  1125.   }
  1126.  
  1127.   // changer les ~,:,",*,? en _ pour sauver sur disque
  1128.   hts_replace(save,'~','_');  // interdit sous unix (~foo)
  1129.   //
  1130.   hts_replace(save,'\\','_');
  1131.   hts_replace(save,':','_');  // interdit sous windows
  1132.   hts_replace(save,'*','_');  // interdit sous windows
  1133.   hts_replace(save,'?','_');  // doit pas arriver!!
  1134.   hts_replace(save,'\"','_');  // interdit sous windows
  1135.   hts_replace(save,'<','_');  // interdit sous windows
  1136.   hts_replace(save,'>','_');  // interdit sous windows
  1137.   hts_replace(save,'|','_');  // interdit sous windows
  1138.   //
  1139.   hts_replace(save,'@','_');
  1140.   if (opt->savename_83 == 2) { // CDROM
  1141.     // maybe other ones?
  1142.     hts_replace(save,'-','_');
  1143.     hts_replace(save,'=','_');
  1144.     hts_replace(save,'+','_');
  1145.   }
  1146.   //
  1147.   { // Θliminer les // (comme ftp://)
  1148.     char* a;
  1149.     while( (a=strstr(save,"//")) ) *a='_';
  1150.     // Eliminer chars spΘciaux
  1151.     a=save -1 ;
  1152.     while(*(++a))
  1153.       if ( ((unsigned char)(*a) <= 31)
  1154.           || ((unsigned char)(*a) == 127) )
  1155.         *a='_';
  1156.   }
  1157.  
  1158.    
  1159. #if HTS_OVERRIDE_DOS_FOLDERS
  1160.   /* Replace /foo/nul/bar by /foo/nul_/bar */
  1161.   {
  1162.     int i=0;
  1163.     while(hts_tbdev[i][0]) {
  1164.       char* a=save;
  1165.       while((a=strstrcase(a,(char*)hts_tbdev[i]))) {
  1166.         switch ( (int) a[strlen(hts_tbdev[i])] ) {
  1167.         case '\0':
  1168.         case '/':
  1169.         case '.': 
  1170.         {
  1171.           char BIGSTK tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0';
  1172.           strncatbuff(tempo,save,(int) (a - save) + strlen(hts_tbdev[i]));
  1173.           strcatbuff(tempo,"_");
  1174.           strcatbuff(tempo,a+strlen(hts_tbdev[i]));
  1175.           strcpybuff(save,tempo);
  1176.                    }
  1177.           break;
  1178.         }
  1179.         a+=strlen(hts_tbdev[i]);
  1180.       }
  1181.       i++;
  1182.     }
  1183.   }
  1184.   /* Strip ending . or ' ' forbidden on windoz */
  1185.   {
  1186.     int len;
  1187.     char* a=save;
  1188.     while((a=strstr(a,"./"))) {
  1189.       *a = '_';
  1190.     }
  1191.     a=save;
  1192.     while((a=strstr(a," /"))) {
  1193.       *a = '_';
  1194.     }
  1195.     len = (int) strlen(save);
  1196.     if (len > 0 && ( save[len - 1] == '.' || save[len - 1] == ' ') ) {
  1197.       save[len - 1] = '_';
  1198.     }
  1199.   }
  1200. #endif
  1201.  
  1202.   // conversion 8-3 .. y compris pour les rΘpertoires
  1203.   if (opt->savename_83) {
  1204.     char BIGSTK n83[HTS_URLMAXSIZE*2];
  1205.     long_to_83(opt->savename_83,n83,save);
  1206.     strcpybuff(save,n83);
  1207.   }
  1208.  
  1209.   // enforce stricter ISO9660 compliance (bug reported by Steffo Carlsson)
  1210.   // Level 1 File names are restricted to 8 characters with a 3 character extension, 
  1211.   // upper case letters, numbers and underscore; maximum depth of directories is 8.
  1212.   // This will be our "DOS mode"
  1213.   // L2: 31 characters
  1214.   // A-Z,0-9,_
  1215.   if (opt->savename_83 > 0) {
  1216.     char *a, *last;
  1217.     for(last = save + strlen(save) - 1 ; last != save && *last != '/' && *last != '\\' && *last != '.' ; last--);
  1218.     if (*last != '.') {
  1219.       last = NULL;
  1220.     }
  1221.     for(a = save ; *a != '\0' ; a++) {
  1222.       if (*a >= 'a' && *a <= 'z') {
  1223.         *a -= 'a' - 'A';
  1224.       }
  1225.       else if (*a == '.') {
  1226.         if (a != last) {
  1227.           *a = '_';
  1228.         }
  1229.       }
  1230.       else if ( ! ( (*a >= 'A' && *a <= 'Z') || (*a >= '0' && *a <= '9') || *a == '_' || *a == '/' || *a == '\\') ) {
  1231.         *a = '_';
  1232.       }
  1233.     }
  1234.   }
  1235.  
  1236.   /* ensure that there is no ../ (potential vulnerability) */
  1237.   fil_simplifie(save);
  1238.  
  1239. #if HTS_ANALYSTE
  1240.   {
  1241.     hts_htmlcheck_savename(adr_complete,fil_complete,referer_adr,referer_fil,save);
  1242.     if ( (opt->debug>0) && (opt->log!=NULL) ) {
  1243.       fspc(opt->log,"info"); fprintf(opt->log,"engine: save-name: local name: %s%s -> %s"LF,adr,fil,save);
  1244.       test_flush;
  1245.     }
  1246.   }
  1247. #endif
  1248.  
  1249.   // chemin primaire Θventuel A METTRE AVANT
  1250.   if (strnotempty(opt->path_html)) {
  1251.     char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1252.     strcpybuff(tempo,opt->path_html);
  1253.     strcatbuff(tempo,save);
  1254.     strcpybuff(save,tempo);
  1255.   }
  1256.  
  1257.  
  1258.   // vΘrifier que le nom n'est pas dΘja pris...
  1259.   if (liens!=NULL) { 
  1260.     int nom_ok;
  1261.     do {
  1262.       int i;
  1263.       int len;
  1264.       len=strlen(save);    // taille
  1265.       //
  1266.       nom_ok=1;  // α priori bon
  1267.       // on part de la fin pour optimiser, plus les opti de taille pour aller encore plus vite..
  1268. #if DEBUG_SAVENAME
  1269. printf("\nStart search\n");
  1270. #endif
  1271.  
  1272. #if HTS_HASH
  1273.       i=hash_read(hash,save,"",0,0);      // lecture type 0 (sav)
  1274.       if (i>=0)
  1275. #else
  1276.       for(i=lien_tot-1;i>=0;i--) {
  1277. #if DEBUG_SAVENAME
  1278. printf("%cParse: %d",13,i);
  1279. #endif
  1280.         
  1281.         if (liens[i]->sav_len==len) {    // mΩme taille de chaεne          
  1282. #if HTS_CASSE
  1283.           if (strcmp(liens[i]->sav,save)==0)    // existe dΘja
  1284. #else
  1285.           if (strfield2(liens[i]->sav,save))    // un tel nom existe dΘja
  1286. #endif
  1287. #endif
  1288.           {
  1289. #if HTS_CASSE
  1290.             if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0))
  1291. #else
  1292.             if ((strfield2(liens[i]->adr, normadr)) && (strfield2(liens[i]->fil, normfil)))
  1293.             //if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete)))
  1294. #endif
  1295.             {    // ok c'est le mΩme lien, adresse dΘja dΘfinie
  1296.               /* Take the existing name not to screw up with cAsE sEnSiTiViTy of Linux/Unix */
  1297.               if (strcmp(liens[i]->sav, save) != 0) {
  1298.                 strcpybuff(save, liens[i]->sav);
  1299.               }
  1300.               i=0;
  1301. #if DEBUG_SAVENAME
  1302. printf("\nOK ALREADY DEFINED\n",13,i);
  1303. #endif
  1304. #if HTS_CASSE
  1305. #endif
  1306.             } else {  // utilisΘ par un AUTRE, changer de nom
  1307.               char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1308.               char* a=save+strlen(save)-1;
  1309.               char* b;
  1310.               int n=2;       
  1311.               tempo[0]='\0';
  1312.  
  1313. #if DEBUG_SAVENAME
  1314. printf("\nWRONG CASE UNMATCH : \n%s\n%s, REDEFINE\n",liens[i]->fil,fil_complete);
  1315. #endif
  1316.               nom_ok=0;
  1317.               i=0;
  1318.               
  1319.               while(( a > save) && (*a!='.') && (*a!='\\') && (*a!='/')) a--;
  1320.               if (*a=='.')
  1321.                 strncatbuff(tempo,save,(int) (a - save));
  1322.               else
  1323.                 strcatbuff(tempo,save);
  1324.               
  1325.               // tester la prΘsence d'un -xx (ex: index-2.html -> index-3.html)
  1326.               b=tempo+strlen(tempo)-1;
  1327.               while (isdigit((unsigned char)*b)) b--;
  1328.               if (*b=='-') {
  1329.                 sscanf(b+1,"%d",&n);
  1330.                 *b='\0';    // couper
  1331.                 n++;  // plus un
  1332.               }
  1333.               
  1334.               // en plus il faut gΘrer le 8-3 .. pas facile le client
  1335.               if (opt->savename_83) {
  1336.                 int max;
  1337.                 char* a=tempo+strlen(tempo)-1;
  1338.                 while(( a > tempo) && (*a!='/')) a--;
  1339.                 if (*a=='/') a++;
  1340.                 max=max_char-1-nombre_digit(n);
  1341.                 if ((int) strlen(a)>max)
  1342.                   *(a+max)='\0';  // couper sinon il n'y aura pas la place!
  1343.               }
  1344.               
  1345.               // ajouter -xx (ex: index.html -> index-2.html)
  1346.               sprintf(tempo+strlen(tempo),"-%d",n);
  1347.               
  1348.               // ajouter extension
  1349.               if (*a=='.')
  1350.                 strcatbuff(tempo,a);
  1351.               
  1352.               strcpybuff(save,tempo);
  1353.               
  1354.               //printf("switched: %s\n",save);
  1355.               
  1356.             }  // if
  1357. #if HTS_HASH
  1358.           }
  1359. #else
  1360.           }  // if
  1361.         }  // if sav_len
  1362.       }  // for
  1363. #endif
  1364. #if DEBUG_SAVENAME
  1365. printf("\nEnd search, %s\n",fil_complete);
  1366. #endif
  1367.     } while(!nom_ok);
  1368.     
  1369.   }
  1370.   
  1371.   //printf("'%s' %s %s\n",save,adr,fil);
  1372.       
  1373.   return 0;
  1374. }
  1375.  
  1376. /* nom avec md5 urilisΘ partout */
  1377. void standard_name(char* b,char* dot_pos,char* nom_pos,char* fil_complete,int short_ver) {
  1378.   b[0]='\0';
  1379.   /* Nom */
  1380.   if (dot_pos) {
  1381.     if (!short_ver)    // Noms longs
  1382.       strncatbuff(b,nom_pos,(int) (dot_pos - nom_pos));
  1383.     else
  1384.       strncatbuff(b,nom_pos,min((int) (dot_pos - nom_pos),8));
  1385.   } else {
  1386.     if (!short_ver)    // Noms longs
  1387.       strcatbuff(b,nom_pos);
  1388.     else
  1389.       strncatbuff(b,nom_pos,8);
  1390.   }
  1391.   /* MD5 - 16 bits */
  1392.   strncatbuff(b,url_md5(fil_complete),4);
  1393.   /* Ext */
  1394.   if (dot_pos) {
  1395.     strcatbuff(b,".");
  1396.     if (!short_ver)    // Noms longs
  1397.       strcatbuff(b,dot_pos+1);
  1398.     else
  1399.       strncatbuff(b,dot_pos+1,3);
  1400.   } else {
  1401.     if (!short_ver)    // Noms longs
  1402.       strcatbuff(b,DEFAULT_EXT);    // pas de..
  1403.     else
  1404.       strcatbuff(b,DEFAULT_EXT_SHORT);    // pas de..
  1405.   }
  1406. }
  1407.  
  1408.  
  1409. /* Petit md5 */
  1410. char* url_md5(char* fil_complete) {
  1411.   char* digest;
  1412.   char* a;
  1413.   NOSTATIC_RESERVE(digest, char, 32+2);
  1414.   digest[0]='\0';
  1415.   a=strchr(fil_complete,'?');
  1416.   if (a) {
  1417.     if (strlen(a)) {
  1418.       char BIGSTK buff[HTS_URLMAXSIZE*2];
  1419.       a++;
  1420.       digest[0]=buff[0]='\0';
  1421.       strcatbuff(buff,a);         /* query string MD5 */
  1422.       domd5mem(buff,strlen(buff),digest,1);
  1423.     }
  1424.   }
  1425.   return digest;
  1426. }
  1427.  
  1428. // interne α url_savename: ajoute une chaεne α une autre avec \ -> /
  1429. void url_savename_addstr(char* d,char* s) {
  1430.   int i=strlen(d);
  1431.   while(*s) {
  1432.     if (*s=='\\')  // remplacer \ par des /
  1433.       d[i++]='/';
  1434.     else
  1435.       d[i++]=*s;
  1436.     s++;
  1437.   }
  1438.   d[i]='\0';
  1439. }
  1440.  
  1441. #undef test_flush
  1442.